package etnorservice.etnor_service.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import etnorservice.etnor_service.domain.MenuItemDomain;
import etnorservice.etnor_service.domain.RoleUserDomain;
import etnorservice.etnor_service.domain.UserDomain;
import etnorservice.etnor_service.mapper.RoleUserMapper;
import etnorservice.etnor_service.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: cc
 * @Date: 2025/03/24/12:56
 **/
@Service
@Transactional
@Slf4j
public class UserManagementService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleUserMapper roleUserMapper;

   // @Autowired
    //private PasswordEncoder passwordEncoder;

    public IPage<UserDomain> getUserList(Page<UserDomain> page, String keyword) {
        QueryWrapper<UserDomain> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(keyword)) {
            queryWrapper.like("username", keyword)
                    .or()
                    .like("account", keyword)
                    .or()
                    .like("email", keyword);
        }
        return userMapper.selectPage(page, queryWrapper);
    }

    public UserDomain createUser(UserDomain user) {
        user.setPassword(user.getPassword());
        user.setStatus(1);
        user.setUpdatetime(new Date());
        userMapper.insert(user);
        return user;
    }

    @Transactional(rollbackFor = Exception.class)
    public void assignUserRoles(Integer userId, List<Integer> roleIds, List<String> roleNames) {
        log.info("开始分配用户角色: userId={}, roleIds={}", userId, roleIds);
        try {
            // 参数校验
            validateAssignParameters(userId, roleIds, roleNames);
            // 获取现有角色用于比较
            List<RoleUserDomain> existingRoles = getCurrentUserRoles(userId);
            Set<Integer> existingRoleIds = existingRoles.stream()
                    .map(RoleUserDomain::getRoleId)
                    .collect(Collectors.toSet());
            // 计算角色变更
            Set<Integer> newRoleIds = CollectionUtils.isEmpty(roleIds)
                    ? Collections.emptySet()
                    : new HashSet<>(roleIds);
            boolean hasRoleChanges = !existingRoleIds.equals(newRoleIds);
            if (hasRoleChanges) {
                // 删除原有角色
                if (!existingRoles.isEmpty()) {
                    deleteExistingRoles(userId);
                }
                // 批量插入新角色
                if (!CollectionUtils.isEmpty(roleIds)) {
                    batchInsertNewRoles(userId, roleIds, roleNames);
                }

                log.info("用户角色更新成功: userId={}, oldRoles={}, newRoles={}",
                        userId, existingRoleIds, newRoleIds);
            } else {
                log.info("用户角色无变化，跳过更新: userId={}", userId);
            }

        } catch (Exception e) {
            log.error("分配用户角色失败: userId={}", userId, e);
            throw new RuntimeException("角色分配失败: " + e.getMessage());
        }
    }

    /**
     * 参数校验
     */
    private void validateAssignParameters(Integer userId, List<Integer> roleIds, List<String> roleNames) {
        Assert.notNull(userId, "用户ID不能为空");

        if (!CollectionUtils.isEmpty(roleIds)) {
            Assert.isTrue(!CollectionUtils.isEmpty(roleNames), "角色名称列表不能为空");
            Assert.isTrue(roleIds.size() == roleNames.size(), "角色ID与名称数量不匹配");

            // 检查是否存在空值
            boolean hasNullId = roleIds.stream().anyMatch(Objects::isNull);
            boolean hasEmptyName = roleNames.stream().anyMatch(StringUtils::isEmpty);
            Assert.isTrue(!hasNullId && !hasEmptyName, "角色ID或名称不能为空");
        }
    }

    /**
     * 获取用户当前角色
     */
    private List<RoleUserDomain> getCurrentUserRoles(Integer userId) {
        QueryWrapper<RoleUserDomain> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        return roleUserMapper.selectList(wrapper);
    }

    /**
     * 删除现有角色
     */
    private void deleteExistingRoles(Integer userId) {
        QueryWrapper<RoleUserDomain> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        int deleted = roleUserMapper.delete(wrapper);
        log.debug("删除用户现有角色: userId={}, deleted={}", userId, deleted);
    }

    /**
     * 批量插入新角色
     */
    private void batchInsertNewRoles(Integer userId, List<Integer> roleIds, List<String> roleNames) {
        Date now = new Date();
        List<RoleUserDomain> roleUsers = new ArrayList<>(roleIds.size());

        for (int i = 0; i < roleIds.size(); i++) {
            RoleUserDomain roleUser = new RoleUserDomain();
            roleUser.setUserId(userId);
            roleUser.setRoleId(roleIds.get(i));
            roleUser.setRoleName(roleNames.get(i));
            roleUser.setCreatedAt(now);
            roleUser.setUpdatedAt(now);
            roleUsers.add(roleUser);
        }

        // 批量插入
        for (RoleUserDomain roleUser : roleUsers) {
            roleUserMapper.insert(roleUser);
        }

        log.debug("批量插入新角色完成: userId={}, count={}", userId, roleUsers.size());
    }

    public List<MenuItemDomain> getUserMenus(Integer userId) {
        return userMapper.getUserMenus(userId);
    }

    public List<RoleUserDomain> getAllRoles() {
        // 从角色表获取所有角色
        return roleUserMapper.getAllRoles();
    }


    public List<RoleUserDomain> getUserRoleList(Integer userId) {
        if (userId == null) {
            return new ArrayList<>();
        }
        QueryWrapper<RoleUserDomain> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        return roleUserMapper.selectList(wrapper);
    }
}